package controllers

import (
	"LoginTemplate/models"
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/httplib"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
	"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
	"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
	"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
	"golang.org/x/net/context"
	"log"
	"math/rand"
	"time"
)

type WXController struct {
	BaseController
}

type Order struct {
	Id          int       `json:"id"`
	Name        string    `json:"name"`
	Total       int64     `json:"total"`
	OrderNo     string    `json:"order_no"`
	UserId      int       `json:"user_id"`
	Payment     int       `json:"payment"`
	TimeExpire  time.Time `json:"time_expire"`
	RefundMoney int64     `json:"refund_money"`
	Att         string    `json:"att"`
	PaymentType int       `json:"payment_type"`
}

func (Order) TableName() string {
	return "order"
}

// 微信支付
func (u *WXController) WXPayment() {
	//var (
	//	mchID                      string = "1397856802"                               // 商户号
	//	mchCertificateSerialNumber string = "3AB06EAEC9D2FDFF9AEADE0A8AC259C1863298D1" // 商户证书序列号
	//	mchAPIv3Key                string = "exoclkoqbtneg0iaojhnqlnaff01m3jj"         // 商户APIv3密钥
	//)
	var order Order
	u.ShouldBind(&order)
	mchID := beego.AppConfig.String("mchID")
	mchCertificateSerialNumber := beego.AppConfig.String("mchCertificateSerialNumber")
	mchAPIv3Key := beego.AppConfig.String("mchAPIv3Key")
	Appid := beego.AppConfig.String("Appid")
	url := beego.AppConfig.String("url")
	No := GenerateOrderID()
	println(No)
	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("./path/to/merchant/apiclient_key.pem")
	if err != nil {
		log.Print("load merchant private key error")
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err:%s", err)
	}

	svc := native.NativeApiService{Client: client}
	resp, result, err := svc.Prepay(ctx,
		native.PrepayRequest{
			Appid:       core.String(Appid),
			Mchid:       core.String(mchID),
			Description: core.String(order.Name),
			OutTradeNo:  core.String(No),
			TimeExpire:  core.Time(time.Now()),
			//Attach:        core.String("自定义数据说明"),
			NotifyUrl: core.String(url),
			Amount: &native.Amount{
				Currency: core.String("CNY"),
				//分
				Total: core.Int64(order.Total),
			},
			Attach: core.String(order.Att),
			//结算信息
			/*SceneInfo: &native.SceneInfo{
				DeviceId:      core.String("013467007045764"),
				PayerClientIp: core.String("14.23.150.211"),
				StoreInfo: &native.StoreInfo{
					Address:  core.String("广东省深圳市南山区科技中一道10000号"),
					AreaCode: core.String("440305"),
					Id:       core.String("0001"),
					Name:     core.String("腾讯大厦分店"),
				},
			},*/
		},
	)

	if err != nil {
		// 处理错误
		log.Printf("call Prepay err:%s", err)
	} else {
		formattedTime := time.Now().Format("2006-01-02 15:04:05")
		sql := "insert into `order` (name,total,order_no,user_id,payment,time_expire,payment_type) values (?,?,?,?,?,?,?)"
		models.DB.Debug().Exec(sql, order.Name, order.Total, No, order.UserId, 1, formattedTime, order.PaymentType)
		// 处理返回结果
		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
		value := *resp.CodeUrl
		println("status=", result.Response.StatusCode, "resp=", value)
		erweima := Erweima(value)
		u.JsonMsg(200, map[string]interface{}{
			"list":  erweima,
			"order": No,
			"count": "",
		}, "success")
	}
}

// 生成订单号函数
func GenerateOrderID() string {
	// 使用当前时间戳作为订单号的一部分
	timestamp := time.Now().UnixNano() / int64(time.Millisecond)

	// 使用随机数作为订单号的一部分
	rand.Seed(time.Now().UnixNano())
	randomPart := rand.Intn(1000)

	// 将时间戳和随机数拼接起来作为订单号
	orderID := fmt.Sprintf("%d%d", timestamp, randomPart)

	return orderID
}
func Erweima(wxurl string) string {
	url := "https://cli.im/Apis/QrCode/saveStatic"
	req := httplib.Post(url)
	req.Param("info", wxurl)
	req.Param("content", wxurl)
	req.Param("level", "H")
	req.Param("size", "500")
	req.Param("fgcolor", "#000000")
	req.Param("bggcolor", "#FFFFFF")
	req.Param("transparent", "false")
	req.Param("type", "text")
	req.Param("codetype", "qr")
	req.Param("base64", "")
	req.Param("static_create_from", "10003")
	req.Param("last_code_info", "{\"last_code_id\":857893091,\"last_code_type\":3,\"last_code_small_type\":\"text\"}")
	req.Param("code_small_type", "text")
	req.Param("codeimg", "1")
	// 发送请求并接收响应
	resp, err := req.String()
	if err != nil {
		// 处理错误
		println("生成二维码错误")
	}

	// 打印响应结果
	fmt.Println(resp)
	return resp
}
func (u *WXController) LoopBackAddress() {

}

type PaymentCallback struct {
	Id           string   `json:"id"`
	CreateTime   string   `create_time`
	ResourceType string   `json:"resource_type"`
	EventType    string   `json:"event_type"`
	Summary      string   `json:"summary"`
	Resource     Resource `json:"resource"`
}
type Resource struct {
	OriginalType   string `json:"original_type"`
	Algorithm      string `json:"algorithm"`
	Ciphertext     string `json:"ciphertext"`
	AssociatedData string `json:"associated_data"`
	Nonce          string `json:"nonce"`
}
type Data struct {
	Mchid          string `json:"mchid"`
	Appid          string `json:"appid"`
	OutTradeNo     string `json:"out_trade_no"`
	TransactionId  string `json:"transaction_id"`
	TradeType      string `json:"trade_type"`
	TradeState     string `json:"trade_state"`
	TradeStateDesc string `json:"trade_state_desc"`
	BankType       string `json:"bank_type"`
	Attach         string `json:"attach"`
	SuccessTime    string `json:"success_time"`
	Payer          payer  `json:"payer"`
	Amount         Amount `json:"amount"`
}
type payer struct {
	Openid string `json:"openid"`
}
type Amount struct {
	Total         int    `json:"total"`
	PayerTotal    int    `json:"payer_total"`
	Currency      string `json:"currency"`
	PayerCurrency string `json:"payer_currency"`
}

// 支付回调
func (u *WXController) PaymentCallback() {
	var payment PaymentCallback
	u.ShouldBind(&payment)
	if payment.Summary == "支付成功" {
		mchPrivateKey, _ := utils.LoadPrivateKeyWithPath("./path/to/merchant/apiclient_key.pem")
		mchCertificateSerialNumber := beego.AppConfig.String("mchCertificateSerialNumber")
		mchID := beego.AppConfig.String("mchID")
		mchAPIv3Key := beego.AppConfig.String("mchAPIv3Key")
		request := u.Ctx.Request
		ctx := context.Background()
		// 1. 使用 `RegisterDownloaderWithPrivateKey` 注册下载器
		err := downloader.MgrInstance().RegisterDownloaderWithPrivateKey(ctx, mchPrivateKey, mchCertificateSerialNumber, mchID, mchAPIv3Key)
		if err != nil {
			println(err.Error())
		}
		// 2. 获取商户号对应的微信支付平台证书访问器
		certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
		// 3. 使用证书访问器初始化 `notify.Handler`
		handler := notify.NewNotifyHandler(mchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor))

		transaction := new(payments.Transaction)
		notifyReq, err := handler.ParseNotifyRequest(context.Background(), request, transaction)
		// 如果验签未通过，或者解密失败
		if err != nil {
			fmt.Println(err)
			return
		}
		// 处理通知内容
		fmt.Println(notifyReq.Summary)
		fmt.Println(transaction.TransactionId)
		plaintext := notifyReq.Resource.Plaintext
		var data Data
		err1 := json.Unmarshal([]byte(plaintext), &data)
		if err1 != nil {
			log.Fatal(err1)
		}
		if data.TradeStateDesc == "支付成功" {
			sql := "update `order` set payment = 2 where order_no = ?"
			models.DB.Debug().Exec(sql, data.OutTradeNo)
			sql2 := "select * from dayBook where serial_number = ?"
			var dataBook DataBook
			models.DB.Debug().Raw(sql2, data.TransactionId).Scan(&dataBook)
			if dataBook.SerialNumber == "" {
				sql1 := "insert into dayBook (serial_number,abstract,opposite_accounts,assist,name,account_number,bank_card,income,expenditure,remark)values (?,?,?,?,?,?,?,?,?,?)"
				models.DB.Debug().Exec(sql1, data.TransactionId, "", data.Attach, "", "", "", "", data.Amount.PayerTotal/100, 0, "")
			}

		}
		u.JsonMsg(200, map[string]interface{}{
			"list":  "成功",
			"count": "",
		}, "success")
	}
}

type ErrorResponse struct {
	StatusCode int    `json:"StatusCode"`
	Code       string `json:"Code"`
	Message    string `json:"Message"`
	Header     struct {
		KeepAlive           string `json:"Keep-Alive"`
		WechatpayTimestamp  string `json:"Wechatpay-Timestamp"`
		ContentType         string `json:"Content-Type"`
		Connection          string `json:"Connection"`
		WechatpaySerial     string `json:"Wechatpay-Serial"`
		Server              string `json:"Server"`
		XContentTypeOptions string `json:"X-Content-Type-Options"`
		WechatpaySignature  string `json:"Wechatpay-Signature"`
		ContentLength       string `json:"Content-Length"`
		WechatpayNonce      string `json:"Wechatpay-Nonce"`
		RequestId           string `json:"Request-Id"`
		ContentLanguage     string `json:"Content-Language"`
		CacheControl        string `json:"Cache-Control"`
	} `json:"Header"`
}

// 退款
func (u *WXController) Refund() {
	var order Order
	u.ShouldBind(&order)
	mchID := beego.AppConfig.String("mchID")
	mchCertificateSerialNumber := beego.AppConfig.String("mchCertificateSerialNumber")
	mchAPIv3Key := beego.AppConfig.String("mchAPIv3Key")

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("./path/to/merchant/apiclient_key.pem")
	if err != nil {
		log.Print("load merchant private key error")
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err:%s", err)
	}

	svc := refunddomestic.RefundsApiService{Client: client}
	resp, result, err := svc.Create(ctx,
		refunddomestic.CreateRequest{
			OutTradeNo:  core.String(order.OrderNo),
			OutRefundNo: core.String(order.OrderNo),
			Amount: &refunddomestic.AmountReq{
				Currency: core.String("CNY"),
				Refund:   core.Int64(order.RefundMoney),
				Total:    core.Int64(order.Total),
			},
		},
	)

	if err != nil {
		// 处理错误
		log.Printf("call Create err:%s", err)
		println(err.Error())
		u.JsonMsg(500, map[string]interface{}{
			"list": err.Error(),
		}, "success")
	} else {
		// 处理返回结果
		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
		println("status=", result.Response.StatusCode, "resp=", resp)
	}
}
